﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using YAGMRC.Core;
using YAGMRC.Core.Commands;
using YAGMRC.Core.Models.SubmitTurn;

namespace YAGMRC
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            m_MyTraceListener = new MyTraceListener(WriteTrace, WriteTraceLine);
            Trace.Listeners.Add(m_MyTraceListener);

            m_MainViewModel = new MainViewModel();
            m_Config = new MyConfig();

            InitializeComponent();
        }

        private MainViewModel m_MainViewModel;
        private MyConfig m_Config;
        private MyTraceListener m_MyTraceListener;

        private void WriteTrace(string message)
        {
            if (this.Statuslabel.InvokeRequired)
            {
                this.Invoke(new Action<string>(WriteTrace), new object[] { message });
            }
            else
            {
                this.Statuslabel.Text = message;
                this.Statuslabel.Refresh();
            }
        }

        private void WriteTraceLine(string message)
        {

            if (this.Statuslabel.InvokeRequired)
            {
                this.Invoke(new Action<string>(WriteTraceLine), new object[] { message });
            }
            else
            {
                this.Statuslabel.Text = message;
                this.Statuslabel.Refresh();
            }
        }

        private void ExitButton_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.LoadSettings();

            if (!string.IsNullOrWhiteSpace(this.AuthKeyTextBox.Text))
            {
                this.Authenticate();
            }
        }

        private void LoginButton_Click(object sender, EventArgs e)
        {
            this.Authenticate();
        }

        private void LoadSettings()
        {
            this.AuthKeyTextBox.Text = m_Config.AuthKey;
        }

        private void SaveSettings()
        {
            string authKeyUI = this.AuthKeyTextBox.Text;
            m_Config.AuthKey = authKeyUI;
        }

        private void Authenticate()
        {
            string authKey = m_Config.AuthKey;
            this.AuthKeyTextBox.Text = authKey;

            if (!string.IsNullOrWhiteSpace(authKey))
            {
                var auth = m_MainViewModel.Authenticate;
                auth.Execute(authKey);

                this.UpdateUI();
            }
        }

        private void UpdateUI()
        {
            if (this.MyTurnListBox.InvokeRequired)
            {
                this.Invoke(new Action(UpdateUI), null);
            }
            else
            {
                this.SuspendLayout();

                bool authenticated = m_MainViewModel.Authenticate.Result.Authenticated;
                this.LoggedInCheckBox.Checked = authenticated;

                this.AllGamesListBox.Items.Clear();
                this.MyTurnListBox.Items.Clear();

                if (authenticated)
                {
                    var getGamesAndPlayers = m_MainViewModel.GetGamesAndPlayers;
                    getGamesAndPlayers.Execute();
                    var getGamesAndPlayersResult = getGamesAndPlayers.Result;

                    if (getGamesAndPlayersResult.HasResult)
                    {
                        var games = getGamesAndPlayersResult.Result.Games;
                        foreach (var game in games)
                        {
                            this.AllGamesListBox.Items.Add(new GuiGame(game));
                        }

                        IEnumerable<GuiGame> myTurns = from game in games where (null != game.CurrentTurn) && (Convert.ToInt64(game.CurrentTurn.UserId) == this.m_MainViewModel.Authenticate.Result.PlayerID) select new GuiGame(game);
                        foreach (GuiGame myturn in myTurns)
                        {
                            this.MyTurnListBox.Items.Add(myturn);
                        }
                    }
                }

                this.ResumeLayout(false);
            }
        }

        private void DownloadGame(GuiGame selectedGame)
        {
            if ((null != selectedGame) && (this.m_MainViewModel.Authenticate.Result.Authenticated))
            {
                var cmd = m_MainViewModel.GetLatestSaveFileBytes;
                cmd.Execute(new GetLatestSaveFileBytesCommandParam(selectedGame.Game.GameId));
            }
        }

        private void MyTurnListBox_DoubleClick(object sender, EventArgs e)
        {
            GuiGame selectedGame = MyTurnListBox.SelectedItem as GuiGame;

            if (null == selectedGame)
            {
                return;
            }

            this.SuspendLayout();
            this.FreezeUI(true);


            Action action = new Action(() =>
                {
                    Trace.WriteLine("starting...");

                    Trace.WriteLine("downloading game (takes a while)");
                    DownloadGame(selectedGame);

                    Trace.WriteLine("finished downloading game");               

                    this.Invoke(new Action(() =>
                    {
                        var dialogResult = MessageBox.Show("Launch Steam ?", "Launch Steam", MessageBoxButtons.YesNo);
                        if (dialogResult == System.Windows.Forms.DialogResult.Yes)
                        {
                            Trace.WriteLine("launching steam (takes a while)");
                            this.m_MainViewModel.LaunchSteam.Execute();
                        }
                        
                    }));

                    this.Invoke(new Action(() =>
                    {
                       var dialogResult = MessageBox.Show("Submit Turn ?", "Submit Turn", MessageBoxButtons.YesNo);
                       if (dialogResult == System.Windows.Forms.DialogResult.Yes)
                       {
                           Trace.WriteLine("submitting turn (takes a while)");
                           SubmitTurnCommand submitTurncmd = this.m_MainViewModel.SubmitTurn;
                           submitTurncmd.Execute(new SubmitTurnCommandParam(selectedGame.Game.GameId, true));

                           SubmitTurnResult submitTurnResult = submitTurncmd.Result;

                           this.Invoke(new Action(() =>
                           {
                               MessageBox.Show("Result: " + submitTurnResult.ResultType.ToString() + " Points: " + submitTurnResult.PointsEarned.ToString());
                           }));
                       }
                     }));

                    this.FreezeUI(false);
                    this.ResumeLayout(false);
                    this.UpdateUI();

                    Trace.TraceInformation("finished");
                });

            
            //Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);

            using (BackgroundWorker bw = new BackgroundWorker())
            {
                bw.DoWork += (bwsender, bwe) => action();
                bw.RunWorkerAsync();
            }


        }

        private void FreezeUI(bool freeze)
        {
            if (this.PleaseWaitPictureBox.InvokeRequired)
            {
                this.Invoke(new Action<bool>(FreezeUI), new object[] { freeze });
            }
            else
            {
                this.PleaseWaitPictureBox.Visible = freeze;
                this.LoginButton.Enabled = !freeze;
                this.AuthKeyTextBox.Enabled = !freeze;
                this.MyTurnListBox.Enabled = !freeze;
                this.AllGamesListBox.Enabled = !freeze;
                this.ExitButton.Enabled = !freeze;

                this.Refresh();
            }
        }

        private void AuthKeyTextBox_TextChanged(object sender, EventArgs e)
        {
            this.SaveSettings();
        }
    }
}